package com.xiaoma.aes.encryption.asymmetrical;

import com.xiaoma.aes.util.BaseUtil;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;


/**
 * RSA 加密工具类
 * @author Knight-Ran 2016年4月27日 下午3:59:36
 * @version 0.0.1
 */
public class EncryptTool{
    
    

    
    /**
     * 公钥加密：
     * @param data 需要加密的字符串
     * @param key 公钥 ，十六进制字符串
     * @return string
     * @since 0.0.1
     * @author ranqi
     * @throws Exception
     */
    public static String encryptByPublicKey(String data, String key){
        
        /* 对公钥解密 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(key);
        
        /* 取公钥 */
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        
        KeyFactory keyFactory = null;
        Key publicKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:解密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法({0})不存在", Encrytion.KEY_ALGORTHM);
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        Cipher cipher = null;
        
        try{
            cipher = Cipher.getInstance(Encrytion.CIPHER_ALGORTHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:解密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法({0})不存在", Encrytion.CIPHER_ALGORTHM);
        }catch(NoSuchPaddingException e){
//            LOGGER.error("系统异常:解密算法错误", e);
//            throw new EncryptionException("系统异常:解密算法错误", e);
        }catch(InvalidKeyException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        byte [] dataBytes = null;
        try{
            dataBytes = data.getBytes(Encrytion.CHARSET);
        }catch(UnsupportedEncodingException e){
//            LOGGER.error("业务异常: 加密错误,字符编码(" + Encrytion.CHARSET + ")不支持", e);
//            throw new EncryptionException("业务异常: 加密错误,字符编码{0}不支持", e, Encrytion.CHARSET);
        }
        
        int dataBytesLength = dataBytes.length;
        StringBuffer result = new StringBuffer();
        
        int max = Encrytion.MAX;
        try{
            if(dataBytesLength <= max){
                
                return BaseUtil.parseByte2HexStr(cipher.doFinal(dataBytes));
            }else{
                
                /* 用于对加密的数据分组，计算分组的长度 */
                int size;
                /* 临时数组长度 */
                int len;
                /* 临时数组 */
                byte [] bs;
                int remainderSize = dataBytesLength % max;
                if(remainderSize > 0){
                    size = dataBytesLength / max + 1;
                }else{
                    size = dataBytesLength / max;
                }
                
                for(int i = 0; i < size; i++){
                    
                    if(i == size - 1){
                        if(remainderSize > 0){
                            len = remainderSize;
                        }else{
                            len = max;
                        }
                    }else{
                        len = max;
                    }
                    
                    bs = new byte[len];
                    BaseUtil.arraycopy(dataBytes, i * max, bs, 0, len);
                    String hexStr = BaseUtil.parseByte2HexStr(cipher.doFinal(bs));
                    result.append(hexStr);
                    
                    if(i != size - 1){
                        result.append(Encrytion.SPLIT);
                    }
                    
                }
                return result.toString();
            }
        }catch(IllegalBlockSizeException e){
//            LOGGER.error("业务异常: 解密错误", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }catch(BadPaddingException e){
//            LOGGER.error("业务异常:  解密错误", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }

        return null;
    }
    
    /**
     * 私钥加密：
     * @param data 需要加密的字符串
     * @param key 私钥 ，十六进制字符串
     * @return String
     * @since 0.0.1
     * @author ranqi
     * @throws Exception
     */
    public static String encryptByPrivateKey(String data, String key){
        
        /* 对公钥加密 */
        byte [] keyBytes = BaseUtil.parseHexStr2Byte(key);
        
        /* 取公钥 */
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        
        KeyFactory keyFactory = null;
        Key privateKey = null;
        try{
            keyFactory = KeyFactory.getInstance(Encrytion.KEY_ALGORTHM);
            privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:加密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.KEY_ALGORTHM + ")不存在", e);
        }catch(InvalidKeySpecException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        Cipher cipher = null;
        
        try{
            cipher = Cipher.getInstance(Encrytion.CIPHER_ALGORTHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
        }catch(NoSuchAlgorithmException e){
//            LOGGER.error("系统异常:加密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在", e);
//            throw new EncryptionException("系统异常:加密算法(" + Encrytion.CIPHER_ALGORTHM + ")不存在", e);
        }catch(NoSuchPaddingException e){
//            LOGGER.error("系统异常:加密算法错误", e);
//            throw new EncryptionException("系统异常:加密算法错误", e);
        }catch(InvalidKeyException e){
//            LOGGER.error("业务异常: 秘钥获取失败", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        
        byte [] dataBytes = null;
        try{
            dataBytes = data.getBytes(Encrytion.CHARSET);
        }catch(UnsupportedEncodingException e){
//            LOGGER.error("业务异常: 加密错误,字符编码(" + Encrytion.CHARSET + ")不支持", e);
//            throw new EncryptionException("业务异常: 加密错误,字符编码" + Encrytion.CHARSET + "不支持", e);
        }
        
        int dataBytesLength = dataBytes.length;
        StringBuffer result = new StringBuffer();
        
        int max = Encrytion.MAX;
        try{
            if(dataBytesLength <= max){
                
                return BaseUtil.parseByte2HexStr(cipher.doFinal(dataBytes));
            }else{
                
                /* 用于对加密的数据分组，计算分组的长度*/
                int size;
                /* 临时数组长度 */
                int len;
                /* 临时数组 */
                byte [] bs;
                int remainderSize = dataBytesLength % max;
                if(remainderSize > 0){
                    size = dataBytesLength / max + 1;
                }else{
                    size = dataBytesLength / max;
                }
                
                for(int i = 0; i < size; i++){
                    
                    if(i == size - 1){
                        if(remainderSize > 0){
                            len = remainderSize;
                        }else{
                            len = max;
                        }
                    }else{
                        len = max;
                    }
                    
                    bs = new byte[len];
                    BaseUtil.arraycopy(dataBytes, i * max, bs, 0, len);
                    String hexStr = BaseUtil.parseByte2HexStr(cipher.doFinal(bs));
                    result.append(hexStr);
                    
                    if(i != size - 1){
                        result.append(Encrytion.SPLIT);
                    }
                    
                }
                return result.toString();
            }
        }catch(IllegalBlockSizeException e){
//            LOGGER.error("业务异常: 加密错误", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }catch(BadPaddingException e){
//            LOGGER.error("业务异常:  加密错误", e);
//            throw new EncryptionException("业务异常: 秘钥获取失败", e);
        }
        return null;
    }
    
}
